﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "SingleGridBehaviors.h"
#include "AlgorithmProject.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GbmpModelViewTypes.h"
#include "GbmpModelViewUtil.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "GridNewCommon.h"
#include "ICalculatorCollection.h"
#include "ICurve3d.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IElementModelShape.h"
#include "IElementParentReporter.h"
#include "IElementPositionPoints.h"
#include "IElementShapeHandleBehavior.h"
#include "IElementStatus.h"
#include "IExternalData.h"
#include "IExternalDataComponent.h"
#include "IGenericElement.h"
#include "IGraphicsElementShape.h"
#include "IGraphicsPlane.h"
#include "IGraphicsPoint.h"
#include "IGraphicsStyleManager.h"
#include "IModelView.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IPlane.h"
#include "IRegenerator.h"
#include "SingleGrid.h"
#include "Vector3dUtils.h"
#include "IModelViewEvent.h"
#include "IModelViewEventArgs.h"
#include "NdbUpgrade.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
CREATE_DEBUG_MODE_EXPORT(defRectViewPortChanged, L"轴网随裁剪框变化", gcmp::DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"处理DefRectViewPortChanged使轴网随之变化");

namespace
{
    Vector3d GetControlPoint(const SingleGrid* pGrid, GridControlPointType type, ElementId modelviewId)
    {
        DBG_WARN_AND_RETURN_UNLESS(pGrid, Vector3d::Zero, L"pGrid为空",L"GDMPLab",L"2024-03-30");

        Vector3d ret;
        switch (type)
        {
        case GridControlPointType::HorizontalStart:
            ret = pGrid->GetHorizontalStartPoint(modelviewId);
            break;
        case GridControlPointType::HorizontalEnd:
            ret = pGrid->GetHorizontalEndPoint(modelviewId);
            break;
        case GridControlPointType::VerticalStart:
            ret = pGrid->GetVerticalStartPoint(modelviewId);
            break;
        case GridControlPointType::VerticalEnd:
            ret = pGrid->GetVerticalEndPoint(modelviewId);
            break;
        default:
            break;
        }

        return ret;
    }

    bool SetControlPoint(SingleGrid* pGrid, GridControlPointType type, ElementId modelviewId, const Vector3d& pos)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pGrid, L"pGrid为空",L"GDMPLab",L"2024-03-30");

        switch (type)
        {
        case GridControlPointType::HorizontalStart:
        {
            pGrid->SetHorizontalStartPoint(pos, modelviewId);
            break;
        }
        case GridControlPointType::HorizontalEnd:
        {
            pGrid->SetHorizontalEndPoint(pos, modelviewId);
            break;
        }
        case GridControlPointType::VerticalStart:
        {
            pGrid->SetVerticalStartPoint(pos, modelviewId);
            break;
        }
        case GridControlPointType::VerticalEnd:
        {
            pGrid->SetVerticalEndPoint(pos, modelviewId);
            break;
        }
        default:
            break;
        }

        return true;
    }
}

BEGIN_UPGRADE_CLASS(gcmp, SingleGridViewSpecificShapeComponent, 2)
ADD_OWNERPTR_IDB_PROPERTY(OwnerPtr<IRenderPriorityOffsetProvider>, RenderPriorityOffsetProvider)
END_UPGRADE_CLASS

BEGIN_UPGRADE_CLASS(gcmp, SingleGridViewSpecificShapeComponent, 3)
ADD_OWNERPTR_IDB_PROPERTY(OwnerPtr<IGraphicsNodeVisibilityCustomizer>, GraphicsNodeVisibilityCustomizer)
END_UPGRADE_CLASS

DBOBJECT_DATA_DEFINE(SingleGridViewSpecificShapeComponent)
{
    m_pOwnerElement = nullptr;
    m_GraphicsNodeVisibilityCustomizer = nullptr;
}

bool SingleGridViewSpecificShapeComponent::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    IGraphicsNodeVisibilityCustomizer* pCustomizer = m_GraphicsNodeVisibilityCustomizer.get();
    if (pCustomizer)
    {
        pCustomizer->SetOwnerElement(pOwnerElement);
    }
    return true;
}

bool SingleGridViewSpecificShapeComponent::IsVisibleInModelView(const IModelView* pModelView) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    const IElement *pOwnerElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwnerElement, L"pOwnerElement为空",L"GDMPLab",L"2024-03-30");
    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(pOwnerElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const SingleGrid *pGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGrid, L"pGrid为空",L"GDMPLab",L"2024-03-30");

    if (pModelView->GetDocument() != pGrid->GetDocument()) // 不是同文档的不可见
    {
        return false;
    }

    if (!pGenericElement->GetStatus()->IsVisible())
    {
        return false;
    }

    // 平面视图
    if (PlanViewType == pModelView->GetUserDataId())

    {
        // 轴网垂直向 与 视方向 平行
        if (Vector3dUtils::IsParallel(pGrid->GetVerticalDirection(), pModelView->GetViewDirection()))
        {
            double topOffset = 0.0, bottomOffset = 0.0;
            bool bGetTop = pModelView->GetTopPlaneOffset(topOffset);
            bool bGetBottom = pModelView->GetBottomPlaneOffset(bottomOffset);
            if (bGetTop && bGetBottom)
            {
                Intervald validRange = Intervald::Create(
                    pModelView->GetOrigin().GetZ() + bottomOffset, 
                    pModelView->GetOrigin().GetZ() + topOffset
                );

                // 轴网垂直延伸范围 与 视图顶底范围 相交
                Intervald verticalExtents = pGrid->GetVerticalExtends(pModelView->GetElementId());
                if (!validRange.IsEmpty() && validRange.IsIntersect(verticalExtents))
                {
                    // 才可见
                    return true;
                }
            }
        }
    }
    // 立面视图
    else if ( ElevationViewType == pModelView->GetUserDataId() )

    {
        // 直轴网
        if (pGrid->IsHorizontalStraight())
        {
            Vector3d startPt = pGrid->GetHorizontalStartPoint(pModelView->GetElementId());
            Vector3d endPt = pGrid->GetHorizontalEndPoint(pModelView->GetElementId());
            Vector3d dirHorizontal = Vector3d((endPt - startPt).Vec2d(), 0.0);
            dirHorizontal.Normalize();

            // 轴网水平向 与 视方向 平行
            if (Vector3dUtils::IsParallel(pModelView->GetViewDirection(), dirHorizontal))
            {
                // 才可见
                return true;
            }
        }
    }
    // 剖面视图
    else if ( SectionViewType == pModelView->GetUserDataId() )

    {
        // 直轴网
        if (pGrid->IsHorizontalStraight())
        {
            Vector3d startPt = pGrid->GetHorizontalStartPoint(pModelView->GetElementId());
            Vector3d endPt = pGrid->GetHorizontalEndPoint(pModelView->GetElementId());
            Vector3d dirHorizontal = Vector3d((endPt - startPt).Vec2d(), 0.0);
            dirHorizontal.Normalize();

            // 轴网水平向 与 视方向 平行
            if (Vector3dUtils::IsParallel(pModelView->GetViewDirection(), dirHorizontal))
            {
                // 视口裁剪
                if (pModelView->IsCroppedByViewport())
                {
                    // 剖面视图范围的三维紧包围盒
                    TiltBox3d viewBox;
                    bool bGetViewBox = GbmpModelViewUtil::GetSectionViewBox(pModelView, viewBox);

                    if (bGetViewBox && !viewBox.IsEmpty())
                    {
                        Vector3d projStartPt = Vector3d(startPt.Vec2d(), viewBox.Center().GetZ());
                        Vector3d projEndPt = Vector3d(endPt.Vec2d(), viewBox.Center().GetZ());

                        Vector3d dirLocalY = Vector3d::UnitZ.Cross(dirHorizontal);
                        dirLocalY.Normalize();

                        Coordinate3d localCoord = Coordinate3d::CreateFromAxis(projStartPt, dirHorizontal, dirLocalY);
                        Vector3d localStart = localCoord.GetLocalPoint(projStartPt);
                        Vector3d localEnd = localCoord.GetLocalPoint(projEndPt);
                        Box3d localBox = Box3d::Create(localStart, localEnd);
                        
                        // 构造轴网的三维紧包围盒
                        TiltBox3d gridBox = TiltBox3d::Create(localCoord, localBox);

                        // 两个紧包围盒有交，则可见
                        if (!gridBox.IsEmpty() && gridBox.IsIntersect(viewBox))
                        {
                            return true;
                        }
                    }
                }
                else
                {
                    return true;
                }
            }
        }
    }

    // 其余情况，都不可见
    return false;
}

OwnerPtr<IGraphicsElementShape> gcmp::SingleGridViewSpecificShapeComponent::CreateViewSpecificElementShape(const IModelView* pModelView) const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    const IElement *pOwnerElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pOwnerElement, L"pOwnerElement为空",L"GDMPLab",L"2024-03-30");
    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(pOwnerElement);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const SingleGrid *pGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGrid, L"pGrid为空",L"GDMPLab",L"2024-03-30");

    // 添加到ModelViewEvent监听
    if (pOwnerElement->GetDocument() == pModelView->GetDocument()) // 如果是非链接情况下
    {
        IModelViewEvent* pModelViewEvent = pModelView->GetModelViewEvent();
        DBG_WARN_AND_RETURN_UNLESS(pModelViewEvent != nullptr, nullptr, L"pModelViewEvent为空",L"GDMPLab",L"2024-03-30");
        SingleGridViewSpecificShapeComponent* pSpecificComponent = const_cast<SingleGridViewSpecificShapeComponent*>(this);
        pModelViewEvent->Add(pSpecificComponent);
    }

    return pGrid->CreateElementShapeBasedOnPlane(pModelView->GetWorkPlane().get(), pModelView->GetViewScale(),pModelView);
}

bool SingleGridViewSpecificShapeComponent::NeedsRecreateViewSpecificElementShape(const IModelView* pModelView, const RecreateShapeInfo& shapeInfo) const
{
    if (shapeInfo.Type == RecreateShapeInfo::ModelViewScaleChanged)
        return true;

    return false;
}

void SingleGridViewSpecificShapeComponent::On(IModelViewEventArgs* pArgs)
{
    if (DEBUG_MODE(defRectViewPortChanged))
    {
        if (pArgs &&  pArgs->GetType() == ModelViewEventType::CropBoxChanged)
        {
            IGenericElement* pGenericElement = quick_cast<IGenericElement>(GetOwnerElement());
            DBG_WARN_AND_RETURN_VOID_UNLESS(pGenericElement != nullptr, L"不是一个Level对象",L"GDMPLab",L"2024-03-30");

            IElementStatus* pStatus = pGenericElement->GetStatus();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pStatus != nullptr, L"pStatus为空",L"GDMPLab",L"2024-03-30");

            //TODO: 触发一下对象改变(还是没办法做到仅仅更新所在的视图)
            pStatus->SetIsVisible(!pStatus->IsVisible());
            pStatus->SetIsVisible(!pStatus->IsVisible());
        }
    }
}

void SingleGridViewSpecificShapeComponent::SetRenderPriorityOffsetProvider(OwnerPtr<IRenderPriorityOffsetProvider> opProvider)
{
    SetRenderPriorityOffsetProvider__(TransferOwnership(opProvider));
}

const IRenderPriorityOffsetProvider* SingleGridViewSpecificShapeComponent::GetRenderPriorityOffsetProvider() const
{
    return GetRenderPriorityOffsetProvider__().get();
}

IRenderPriorityOffsetProvider* SingleGridViewSpecificShapeComponent::GetRenderPriorityOffsetProvider()
{
    return GetRenderPriorityOffsetProviderFW__().get();
}

void SingleGridViewSpecificShapeComponent::SetGraphicsNodeVisibilityCustomizer(OwnerPtr<IGraphicsNodeVisibilityCustomizer> opCustomizer)
{
    SetGraphicsNodeVisibilityCustomizer__(TransferOwnership(opCustomizer));
}

const IGraphicsNodeVisibilityCustomizer* SingleGridViewSpecificShapeComponent::GetGraphicsNodeVisibilityCustomizer() const
{
    return GetGraphicsNodeVisibilityCustomizer__().get();
}

IGraphicsNodeVisibilityCustomizer* SingleGridViewSpecificShapeComponent::GetGraphicsNodeVisibilityCustomizer()
{
    return GetGraphicsNodeVisibilityCustomizerFW__().get();
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
IMPLEMENT_CALCULATOR_CREATOR(gcmp, SingleGridGripPointPositionCalculator);

void gcmp::SingleGridGripPointPositionCalculator::ReportInputDataIds(std::vector<RegenDataId> & dataIds) const
{
    IElementShapeHandle* pElementShapeHandle = GetElement<IElementShapeHandle>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle, L"pElementShapeHandle为空",L"GDMPLab",L"2024-03-30");
    IElement* pMasterElem = GetDocument()->GetElement(pElementShapeHandle->GetMasterId());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMasterElem, L"pMasterElem为空",L"GDMPLab",L"2024-03-30");
    dataIds.push_back(pElementShapeHandle->GetMasterIdRdIdForBehavior());
    dataIds.push_back(pMasterElem->GetElementModelShape()->GetGraphicsElementShapeRdId());
    dataIds.push_back(pElementShapeHandle->GetShapeHandlePositionIndexInMasterElementRdId());

    IGenericElement* pGenericElement = quick_cast<IGenericElement>(pMasterElem);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    SingleGrid* pGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGrid, L"pGrid为空",L"GDMPLab",L"2024-03-30");
    dataIds.push_back(pGrid->GetSurfaceAndTerminalsRdId());
    dataIds.push_back(pGrid->GetLeadersRdId());
}

void gcmp::SingleGridGripPointPositionCalculator::Execute()
{
    IElementShapeHandle* pElementShapeHandle = GetElement<IElementShapeHandle>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle, L"pElementShapeHandle为空",L"GDMPLab",L"2024-03-30");

    IElement* pElement = GetDocument()->GetElement(pElementShapeHandle->GetMasterId());
    // The host may have been deleted via undo/redo
    if (nullptr == pElement)
    {
        return;
    }

    IElementShapeHandleBehavior* pElementShapeHandleBehavior = pElementShapeHandle->GetElementShapeHandleBehavior();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandleBehavior, L"pElementShapeHandleBehavior为空",L"GDMPLab",L"2024-03-30");
    pElementShapeHandleBehavior->UpdatePosition();
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(SingleGridGripPointBehavior)
{
    m_Document = nullptr;
}

SingleGridGripPointBehavior::SingleGridGripPointBehavior(IDocument* pDoc, const ElementId& modelViewId)
    : m_Document(pDoc), m_ModelViewId(modelViewId)
{
}

gcmp::OwnerPtr<gcmp::IElementShapeHandleBehavior> SingleGridGripPointBehavior::Create(IDocument* pDoc, const ElementId& modelViewId)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc && modelViewId.IsValid(), L"invalid parameter",L"GDMPLab",L"2024-03-30");
    return NEW_AS_OWNER_PTR(SingleGridGripPointBehavior, pDoc, modelViewId);
}

void gcmp::SingleGridGripPointBehavior::GetCalculators(ICalculatorCollection* calculators) const
{
    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle != nullptr, L"pElementShapeHandle为空",L"GDMPLab",L"2024-03-30");

    ADD_CALCULATOR(SingleGridGripPointPositionCalculator, pElementShapeHandle->GetDocument(), pElementShapeHandle->GetPositionRdIdForBehavior());
    //ADD_CALCULATOR(SingleGridGripPointGRepCalculator, pElementShapeHandle->GetDocument(), pElementShapeHandle->GetElementModelShape()->GetGraphicsElementShapeRdId());
}

bool gcmp::SingleGridGripPointBehavior::Translate(const gcmp::IElementMoveContext & moveContext)
{
    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementShapeHandle != nullptr, L"pElementShapeHandle为空",L"GDMPLab",L"2024-03-30");

    IGenericElement* pGenericElement = quick_cast<IGenericElement>(GetDocument()->GetElement(pElementShapeHandle->GetMasterId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");

    SingleGrid* pGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGrid, L"pGrid为空",L"GDMPLab",L"2024-03-30");

    const IElementShapeHandleBehavior* pElementShapeHandleBehavior = pElementShapeHandle->GetElementShapeHandleBehavior();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementShapeHandleBehavior, L"pElementShapeHandleBehavior为空",L"GDMPLab",L"2024-03-30");

    IModelView* pModelView = quick_cast<IModelView>(GetDocument()->GetElement(pElementShapeHandleBehavior->GetModelViewId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    GridControlPointType type = static_cast<GridControlPointType>(pElementShapeHandle->GetPositionIndexInMasterElement());
    Vector3d pos = GetControlPoint(pGrid, type, pModelView->GetElementId());
    SetControlPoint(pGrid, type, pModelView->GetElementId(), pos + moveContext.GetMoveVector());

    return this->GetDocument()->GetRegenerator()->ForceRegeneratingElements({ pElementShapeHandle->GetElementId() });
}

OwnerPtr<IGraphicsElementShape> SingleGridGripPointBehavior::CreateGrahicsElementShapeInModelView(const IModelView* pModelView) const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView != nullptr, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementShapeHandle != nullptr, L"pElementShapeHandle为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IPlane> opWorkPlane = pModelView->GetWorkPlane();

    // 更新GRep
    OwnerPtr<IGraphicsElementShape> opGGrepNodeRoot = gcmp::IGraphicsElementShape::Create(GraphicsRenderLayer::TransientObject);
    Vector3d position;
    Vector2d uvParameter;
    AlgorithmProject::Project(pElementShapeHandle->GetPosition(), opWorkPlane.get(), uvParameter, position);

    OwnerPtr<IGraphicsPoint> opPoint = IGraphicsPoint::Create(position);
    opPoint->SetDisplayShape(PointDisplayShapeType::Circle);
    opGGrepNodeRoot->AddChild(TransferOwnership(opPoint));
    opGGrepNodeRoot->SetElementId(pElementShapeHandle->GetElementId());
    opGGrepNodeRoot->SetIsClippable(false);

    // 设置属性
    ElementId gstyleId = GetDocument()->GetGraphicsStyleManager()->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_AUXILIARY_ELEMENT);;
    opGGrepNodeRoot->SetGraphicsStyleId(gstyleId);

    return opGGrepNodeRoot;
}

void gcmp::SingleGridGripPointBehavior::ReportParents(IElementParentReporter & reporter) const
{
    reporter.ReportWeak(GetModelViewId());
}

void gcmp::SingleGridGripPointBehavior::GetNearestPoint(Vector3d & nearPoint) const
{
    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle != nullptr, L"pElementShapeHandle指针无效",L"GDMPLab",L"2024-03-30");
    nearPoint = pElementShapeHandle->GetPosition();
}

bool gcmp::SingleGridGripPointBehavior::GetHandleCommandString(const IObject* commandEnvironment, std::wstring & commandStr, gcmp::CommandParameters & cmdParams) const
{
    return false;
}

void gcmp::SingleGridGripPointBehavior::UpdatePosition()
{
    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle != nullptr, L"pElementShapeHandle指针无效",L"GDMPLab",L"2024-03-30");

    IGenericElement* pGenericElement = quick_cast<IGenericElement>(GetDocument()->GetElement(pElementShapeHandle->GetMasterId()));
    if (!pGenericElement)
    {
        return;
    }

    const SingleGrid* pGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGrid && pGrid->GetOwnerElement(), L"pGrid为空",L"GDMPLab",L"2024-03-30");

    const IElementPositionPoints* pBehavior = pGrid->GetOwnerElement()->GetPositionPoints();
    if (pBehavior)
    {
        GridControlPointType type = static_cast<GridControlPointType>(pElementShapeHandle->GetPositionIndexInMasterElement());
        Vector3d pos = GetControlPoint(pGrid, type, this->GetModelViewId());
        pElementShapeHandle->SetPosition(pos);
    }
}



IElementShapeHandle * gcmp::SingleGridGripPointBehavior::GetElementShapeHandle() const
{
    return quick_cast<IElementShapeHandle>(m_Document->GetElement(m_ElementShapeHandleId));
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(SingleGridUiManipulatorComponent)
{
    m_pOwnerElement = nullptr;
}

gcmp::ElementId gcmp::SingleGridUiManipulatorComponent::CreateGripPoint(GridControlPointType type, const gcmp::ElementId& modelviewId) const
{
    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(m_pOwnerElement);
    DBG_WARN_AND_RETURN_UNLESS(pGenericElement, ElementId::InvalidID, L"pGenericElement为空。",L"GDMPLab",L"2024-03-30");
    const SingleGrid* pGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_UNLESS(pGrid, ElementId::InvalidID, L"pGrid为空。",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IElementShapeHandleBehavior> pGripPointBehavior = SingleGridGripPointBehavior::Create(m_pOwnerElement->GetDocument(), modelviewId);
    //std::vector<Int64> snapPriorityTypes;
    //snapPriorityTypes.emplace_back(typeid(SingleGrid).hash_code());
    //pGripPointBehavior->SetSnapPriorityTypes(snapPriorityTypes);
    Vector3d pos = GetControlPoint(pGrid, type, modelviewId);

    IElementShapeHandle* pGripPoint = IElementShapeHandle::Create(
        TransferOwnership(pGripPointBehavior),
        pGenericElement->GetElementId(),
        pos, static_cast<int>(type));
    DBG_WARN_AND_RETURN_UNLESS(pGripPoint != nullptr, ElementId::InvalidID, L"pGripPoint为空",L"GDMPLab",L"2024-03-30");



    return pGripPoint->GetElementId();
}

//////////////////////////////////////////////////////////////////////////////////////////////////////

DBOBJECT_DATA_DEFINE(SingleGridTransformationComponent)
{
    m_pOwnerElement = nullptr;
}

bool SingleGridTransformationComponent::CanBeMoved(std::wstring* explanation/* = nullptr*/) const
{
    SAFE_INIT_POINTER(explanation, L"");

    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(m_pOwnerElement.Get());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const SingleGrid* pGrid = dynamic_cast<const SingleGrid*>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGrid, L"pGrid为空",L"GDMPLab",L"2024-03-30");

    if (pGrid->IsOverridedByAnyModelView())
    {
        // TODO 如何用交互询问？
    }

    return pGenericElement->GetStatus()->CanBeMoved();
}

bool SingleGridTransformationComponent::Translate(const IElementMoveContext& moveContext)
{
    Vector3d moveDir = moveContext.GetMoveVector();
    Matrix4d translationMat;
    translationMat.MakeTranslate(moveDir.X(), moveDir.Y(), moveDir.Z());
    return this->Transform(translationMat);
}

bool SingleGridTransformationComponent::CanBeRotated(std::wstring* explanation/* = nullptr*/) const
{
    SAFE_INIT_POINTER(explanation, L"");

    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(m_pOwnerElement.Get());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const SingleGrid* pGrid = dynamic_cast<const SingleGrid*>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGrid, L"pGrid为空",L"GDMPLab",L"2024-03-30");

    if (pGrid->IsOverridedByAnyModelView())
    {
        // TODO 如何用交互询问？
    }

    return pGenericElement->GetStatus()->CanBeRotated();
}

bool SingleGridTransformationComponent::Rotate(const Vector3d& pointOnVec, const Vector3d& rotateDir, double rotateAngle)
{
    Matrix4d rotationMat;
    rotationMat.MakeRotate(pointOnVec, rotateDir, rotateAngle);
    return this->Transform(rotationMat);
}

bool SingleGridTransformationComponent::Transform(const Matrix4d& matrix)
{
    IGenericElement* pGenericElement = quick_cast<IGenericElement>(m_pOwnerElement.Get());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    SingleGrid* pGrid = dynamic_cast<SingleGrid*>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGrid, L"pGrid为空",L"GDMPLab",L"2024-03-30");

    return pGrid->Transform(matrix);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(SingleGridCopyPasteComponent)
{
    m_pOwnerElement = nullptr;
}
void gcmp::SingleGridCopyPasteComponent::UpdateAfterCopy(const ICopyContext& copyContext)
{
    IGenericElement* pGrenericElement = quick_cast<IGenericElement>(m_pOwnerElement);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGrenericElement, L"pGrenericElement为空，不合法",L"GDMPLab",L"2024-03-30");

    SingleGrid* pGrid = quick_cast<SingleGrid>(pGrenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGrid, L"pGrid为空，不合法",L"GDMPLab",L"2024-03-30");

    pGrid->AutoName();

    //// 触发视图树刷新
    //BROADCAST_MESSAGE(ViewMessageListener::MessageUpdatePropertyPanel);
}

bool gcmp::SingleGridCopyPasteComponent::CanBeCopied(std::wstring * pErrorMessage) const
{
    const IElement * pIElement = GetOwnerElement();;
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pIElement, L"获取IElement指针失败",L"GDMPLab",L"2024-03-30");
    if (const IExternalDataComponent * pExternalDataComponent = pIElement->GetExternalDataComponent())
    {
        const std::vector<OwnerPtr<IExternalData>>& externalDatas = pExternalDataComponent->GetAllExternalDatas();
        FOR_EACH(externalData, externalDatas)
        {
            if (!externalData)
            {
                continue;
            }
            std::wstring explanationString;
            if (!externalData->CanBeCopied(&explanationString))
            {
                SAFE_INIT_POINTER(pErrorMessage, explanationString);
                return false;
            }
        }
    }
    return true;
}

bool gcmp::SingleGridCopyPasteComponent::IsStrongParentsNeedCopied() const
{
    const IElement * pIElement = GetOwnerElement();;
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pIElement, L"获取IElement指针失败",L"GDMPLab",L"2024-03-30");
    if (const IExternalDataComponent * pExternalDataComponent = pIElement->GetExternalDataComponent())
    {
        const std::vector<OwnerPtr<IExternalData>>& externalDatas = pExternalDataComponent->GetAllExternalDatas();
        FOR_EACH(externalData, externalDatas)
        {
            if (!externalData)
            {
                continue;
            }
            if (externalData->IsStrongParentsNeedCopied())
            {
                return true;
            }
        }
    }
    return false;
}

bool gcmp::SingleGridCopyPasteComponent::ShouldBeCopiedTogether(const ICopyContext & copyContext) const
{
    const IElement * pIElement = GetOwnerElement();;
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pIElement, L"获取IElement指针失败",L"GDMPLab",L"2024-03-30");
    if (const IExternalDataComponent * pExternalDataComponent = pIElement->GetExternalDataComponent())
    {
        const std::vector<OwnerPtr<IExternalData>>& externalDatas = pExternalDataComponent->GetAllExternalDatas();
        FOR_EACH(externalData, externalDatas)
        {
            if (!externalData)
            {
                continue;
            }
            if (!externalData->ShouldBeCopiedTogether(copyContext))
            {
                return false;
            }
        }
    }
    return true;
}

void gcmp::SingleGridCopyPasteComponent::UpdateForWeakParentCopied(const IDocument * pDocFrom, const IElement * pSource, const IElement * pCopy) const
{
    const IElement * pIElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIElement, L"获取IElement指针失败",L"GDMPLab",L"2024-03-30");
    if (const IExternalDataComponent * pExternalDataComponent = pIElement->GetExternalDataComponent())
    {
        const std::vector<OwnerPtr<IExternalData>>& externalDatas = pExternalDataComponent->GetAllExternalDatas();
        FOR_EACH(externalData, externalDatas)
        {
            if (!externalData)
            {
                continue;
            }
            externalData->UpdateForWeakParentCopied(pDocFrom, pSource, pCopy);
        }
    }
}

IDocument * gcmp::SingleGridCopyPasteComponent::GetDocument() const
{
    if (!m_pOwnerElement)
    {
        return nullptr;
    }
    return m_pOwnerElement->GetDocument();
}

ElementId gcmp::SingleGridCopyPasteComponent::GetOwnerElementId() const
{
    if (!m_pOwnerElement)
    {
        return ElementId::InvalidID;
    }
    return m_pOwnerElement->GetElementId();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(SingleGridParametersCustomizer)
{
    SetOwnerElement(nullptr);
}
SingleGridParametersCustomizer::SingleGridParametersCustomizer(const IElement* pElement)
    : m_pOwnerElement(const_cast<IElement*>(pElement))
{

}

OwnerPtr<IParameter> SingleGridParametersCustomizer::GetNativeParameter(int paramDefId) const
{
    const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(this->GetOwnerElement());
    DBG_WARN_AND_RETURN_UNLESS(pGenericElement, nullptr, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const SingleGrid* pGrid = quick_cast<const SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_UNLESS(pGrid, nullptr, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IParameter> param;
    // 内建参数
    if (paramDefId == PARAMETER_ID(ElementNameBuiltInParameter))
    {
        //param = NEW_AS_OWNER_PTR(Parameter, GetDocument(), ParameterStorageType::String, false, false, 
            //true, PARAMETER_UID(ElementNameBuiltInParameter), ParameterProcessType::GeneralInput);
        ParameterAttributes pa = {false, false, true};
        param = IParameter::CreateParameter(GetDocument(), ParameterStorageType::String, pa,
            PARAMETER_UID(ElementNameBuiltInParameter), ParameterProcessType::GeneralInput);
        param->SetValueAsString(pGrid->GetName());
        return TransferOwnership(param);
    }

    if (paramDefId == PARAMETER_ID(GridStartTagVisibilityInPlanViewBuiltInParameter))
    {
        //param = NEW_AS_OWNER_PTR(Parameter, GetDocument(), ParameterStorageType::Bool, false, false, 
            //true, PARAMETER_UID(GridStartTagVisibilityInPlanViewBuiltInParameter), ParameterProcessType::GeneralInput);
        ParameterAttributes pa = {false, false, true};
        param = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Bool, pa, 
            PARAMETER_UID(GridStartTagVisibilityInPlanViewBuiltInParameter), ParameterProcessType::GeneralInput);
        param->SetValueAsBool(pGrid->IsStartTagVisibleInPlanView());
        return TransferOwnership(param);
    }
    else if (paramDefId == PARAMETER_ID(GridEndTagVisibilityInPlanViewBuiltInParameter))
    {
        //param = NEW_AS_OWNER_PTR(Parameter, GetDocument(), ParameterStorageType::Bool, false, false, 
            //true, PARAMETER_UID(GridEndTagVisibilityInPlanViewBuiltInParameter), ParameterProcessType::GeneralInput);
        ParameterAttributes pa = {false, false, true};
        param = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Bool, pa, 
            PARAMETER_UID(GridEndTagVisibilityInPlanViewBuiltInParameter), ParameterProcessType::GeneralInput);
        param->SetValueAsBool(pGrid->IsEndTagVisibleInPlanView());
        return TransferOwnership(param);
    }

    return nullptr;
}

bool SingleGridParametersCustomizer::SetNativeParameter(const IParameter *param, std::wstring* errorMsg)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMPLab",L"2024-03-30");

    if (errorMsg)
    {
        errorMsg->clear();
    }

    IGenericElement* pGenericElement = quick_cast<IGenericElement>(this->GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    SingleGrid* pGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGrid, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");

    if (param->GetParameterDefinitionId() == PARAMETER_ID(GridStartTagVisibilityInPlanViewBuiltInParameter))
    {
        bool isStartTagVisible = param->GetValueAsBool();
        pGrid->SetStartTagVisibleInPlanView(isStartTagVisible);
        return true;
    }
    else if (param->GetParameterDefinitionId() == PARAMETER_ID(GridEndTagVisibilityInPlanViewBuiltInParameter))
    {
        bool isEndTagVisible = param->GetValueAsBool();
        pGrid->SetEndTagVisibleInPlanView(isEndTagVisible);
        return true;
    }
    else if (param->GetParameterDefinitionId() == PARAMETER_ID(ElementNameBuiltInParameter))
    {
        return pGrid->SetName(param->GetValueAsString(), errorMsg);
    }

    return false;
}

void SingleGridParametersCustomizer::ReportParameterDefinitions(std::vector<int>* pParamDefIds) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDefIds != nullptr, L"pParamDefUids为空",L"GDMPLab",L"2024-03-30");
    // 内建参数
    pParamDefIds->push_back(PARAMETER_ID(ElementNameBuiltInParameter));
    pParamDefIds->push_back(PARAMETER_ID(GridStartTagVisibilityInPlanViewBuiltInParameter));
    pParamDefIds->push_back(PARAMETER_ID(GridEndTagVisibilityInPlanViewBuiltInParameter));
}

bool SingleGridParametersCustomizer::IsPresetParameter(const UniIdentity& paramDefUid) const
{
    const IElementBasicInformation* pBasicInfo = m_pOwnerElement->GetBasicInformation();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInfo, L"element basic information is null.",L"GDMPLab",L"2024-03-30");
    const UniIdentity& categoryUid = pBasicInfo->GetCategoryUid();

    if (categoryUid.HasSameValue(BuiltInCategoryUniIdentities::BICU_NEW_GRID))
    {
        if (paramDefUid.HasSameValue(PARAMETER_DEF(ElementNameBuiltInParameter)->GetUid()) ||
            paramDefUid.HasSameValue(PARAMETER_DEF(GridStartTagVisibilityInPlanViewBuiltInParameter)->GetUid()) ||
            paramDefUid.HasSameValue(PARAMETER_DEF(GridEndTagVisibilityInPlanViewBuiltInParameter)->GetUid()))
        {
            return true;
        }
    }

    return false;
}

IDocument * gcmp::SingleGridParametersCustomizer::GetDocument() const
{
    if (!m_pOwnerElement)
    {
        return nullptr;
    }
    return m_pOwnerElement->GetDocument();
}

ElementId gcmp::SingleGridParametersCustomizer::GetOwnerElementId() const
{
    if (!m_pOwnerElement)
    {
        return ElementId::InvalidID;
    }
    return m_pOwnerElement->GetElementId();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(SingleGridOffsetComponent)
{
    m_pOwnerElement = nullptr;
}


bool SingleGridOffsetComponent::CanBeOffset(std::wstring* explanation /*= nullptr*/) const
{
    return true;
}

std::vector<OwnerPtr<ICurve3d>> SingleGridOffsetComponent::GetOffsetBaseCurves(const IPlane* pBasePlane) const
{
    std::vector<OwnerPtr<ICurve3d>> vOffsetBaseCurves;
    const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(GetOwnerElement());
    DBG_WARN_AND_RETURN_UNLESS(pGenericElement, vOffsetBaseCurves, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const SingleGrid* pSingleGrid = quick_cast<const SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_UNLESS(pSingleGrid, vOffsetBaseCurves, L"pModelLine为空",L"GDMPLab",L"2024-03-30");

    if (Vector3dUtils::IsParallel(pBasePlane->GetNormal(), Vector3d::UnitZ))
    {
        std::vector<OwnerPtr<ICurve3d>>  HorizentalCurves = pSingleGrid->GetHorizontalGridCurves();
        OwnerPtr<ICurve3d> opCurve3d = HorizentalCurves.size() > 0 ? TransferOwnership(HorizentalCurves[0]) : nullptr;
        OwnerPtr<const gcmp::ICurve3d> opResultCurve3d = AlgorithmProject::ProjectReturnCurve3d(opCurve3d.get(), pBasePlane);
        DBG_WARN_AND_RETURN_UNLESS(opResultCurve3d, vOffsetBaseCurves, L"opResultCurve3d为空",L"GDMPLab",L"2024-03-30");
        vOffsetBaseCurves.emplace_back(TransferOwnership(opResultCurve3d));

    }
    else if (Vector3dUtils::IsPerpendicular(pBasePlane->GetNormal(), Vector3d::UnitZ))
    {
        OwnerPtr<ICurve3d>  VerticalCurves = pSingleGrid->GetVerticalGridCurve();
        OwnerPtr<const gcmp::ICurve3d> opResultCurve3d = AlgorithmProject::ProjectReturnCurve3d(VerticalCurves.get(), pBasePlane);
        DBG_WARN_AND_RETURN_UNLESS(opResultCurve3d, vOffsetBaseCurves, L"opResultCurve3d为空",L"GDMPLab",L"2024-03-30");
        vOffsetBaseCurves.emplace_back(TransferOwnership(opResultCurve3d));
    }
    return vOffsetBaseCurves;
}

bool SingleGridOffsetComponent::SetOffsetBaseCurves(const IPlane* pBasePlane, const std::vector<const ICurve3d *>& vCurves)
{
    if (vCurves.empty())
    {
        return false;
    }

    DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasePlane, L"pBasePlane为空",L"GDMPLab",L"2024-03-30");
    IGenericElement* pGenericElement = quick_cast<IGenericElement>(GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    SingleGrid* pSingleGrid = quick_cast<SingleGrid>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSingleGrid, L"pSingleGrid为空",L"GDMPLab",L"2024-03-30");
    const ICurve3d *pCurve = vCurves[0];
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurve, L"pCurve为空",L"GDMPLab",L"2024-03-30");
    bool Bok = false;

    if (Vector3dUtils::IsParallel(pBasePlane->GetNormal(), Vector3d::UnitZ))
    {
        OwnerPtr<const gcmp::ICurve2d> opCurve2d = AlgorithmProject::Project(pCurve, pBasePlane);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opCurve2d, L"opCurve2d为空",L"GDMPLab",L"2024-03-30");
        const std::vector<const ICurve2d*> HorizentalCurves{ opCurve2d.get() };
        Bok = pSingleGrid->SetHorizontalGridCurves(HorizentalCurves);

    }
    else if (Vector3dUtils::IsPerpendicular(pBasePlane->GetNormal(), Vector3d::UnitZ))
    {
        Vector3d offsetVerticalCurveStartPoint, preOffsetVerticalCurveStartPoint;
        {
            offsetVerticalCurveStartPoint = pCurve->GetStartPoint();
            OwnerPtr<ICurve3d> preVerticalCurve = pSingleGrid->GetVerticalGridCurve();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(preVerticalCurve, L"preVerticalCurve为空",L"GDMPLab",L"2024-03-30");
            preOffsetVerticalCurveStartPoint = preVerticalCurve.get()->GetStartPoint();
        }
        Vector3d Position, prePosition;
        {
            Vector2d uvParameter;
            AlgorithmProject::Project(offsetVerticalCurveStartPoint, pBasePlane, uvParameter, Position);
            AlgorithmProject::Project(preOffsetVerticalCurveStartPoint, pBasePlane, uvParameter, prePosition);
        }
        Vector3d offsetDir = Position - prePosition;//平移的方向向量
        OwnerPtr<IPlane> opHorizentalPlane = IPlane::Create(Vector3d::Zero, Vector3d::UnitZ);//3dcurve的投影平面
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opHorizentalPlane, L"opHorizentalPlane为空",L"GDMPLab",L"2024-03-30");

        std::vector<OwnerPtr<ICurve3d>>  opreHorizental3dCurves = pSingleGrid->GetHorizontalGridCurves();
        std::vector<OwnerPtr<const ICurve2d>> opCastResult2dCurves;
        std::vector<const ICurve2d*> pResultCurve2ds;//轴网水平面上的投影线

        FOR_EACH(curves, opreHorizental3dCurves)
        {
            OwnerPtr<ICurve3d>horizental3dCurve;
            horizental3dCurve = TransferOwnershipCast<ICurve3d>(curves.get()->Clone());
            horizental3dCurve->Translate(offsetDir);
            opCastResult2dCurves.push_back(TransferOwnership(AlgorithmProject::Project(horizental3dCurve.get(), opHorizentalPlane.get())));
        }
        FOR_EACH(curves, opCastResult2dCurves)
        {
            pResultCurve2ds.push_back(curves.get());
        }

        Bok = pSingleGrid->SetHorizontalGridCurves(pResultCurve2ds);
    }
    return Bok;
}
